package studio.xiaoyun.core.xstream;

import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.core.util.HierarchicalStreams;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.mapper.Mapper;

import java.util.Map;

/**
 * 实现Map和xml之间的转换，如果Map的key是字符串类型的，则key作为节点的名称。
 * <p>例如:</p>
 * new StringKeyMapConverter(xstream.getMapper(),"array","key","value");
 * <pre>
 * &lt;map&gt;
 *   &lt;array&gt;
 *     &lt;key&gt;keyValue&lt;/key&gt;
 *     &lt;value&gt;0&lt;/value&gt;
 *   &lt;/array&gt;
 * &lt;/map&gt;
 * </pre>
 * <p>如果Map的key是字符串类型的：</p>
 * <pre>
 * &lt;map&gt;
 *     &lt;key&gt;value&lt;/key&gt;
 * &lt;/map&gt;
 * </pre>
 */
public class StringKeyMapConverter extends MapConverter {

    private final String entryName;
    private final String keyName;
    private final String valueName;
    private final Mapper mapper;

    public StringKeyMapConverter(Mapper mapper){
        super(mapper);
        this.mapper = mapper;
        entryName = "array";
        keyName = "key";
        valueName = "value";
    }
    /**
     * @param mapper mapper
     * @param entryName entry的名称
     * @param keyName key的名称
     * @param valueName value的名称
     */
    public StringKeyMapConverter(Mapper mapper, String entryName, String keyName,String valueName) {
        super(mapper);
        this.mapper = mapper;
        this.entryName = entryName;
        this.keyName = keyName;
        this.valueName = valueName;
    }

    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
        Map map = (Map) source;
        boolean isStringKey = true;
        //判断Map的key是否都是字符串类型
        for(Object key : map.keySet()){
            if(key!=null && key.getClass()!=String.class){
                isStringKey = false;
                break;
            }
        }
        for (Object o : map.entrySet()) {
            Map.Entry entry = (Map.Entry) o;
            if (entry.getKey() == null || entry.getValue() == null) continue;
            if(isStringKey){  //如果key是字符串类型，则key作为xml的标签
                writer.startNode(entry.getKey().toString());
                writer.addAttribute(mapper.aliasForSystemAttribute("class"), mapper.serializedClass(entry.getValue().getClass()));
                context.convertAnother(entry.getValue());
                writer.endNode();
            }else{
                writer.startNode(entryName);
                writer.addAttribute(mapper.aliasForSystemAttribute("class"), entryName);
                writer.startNode(keyName);
                writer.addAttribute(mapper.aliasForSystemAttribute("class"), mapper.serializedClass(entry.getKey().getClass()));
                context.convertAnother(entry.getKey());
                writer.endNode();
                writer.startNode(valueName);
                writer.addAttribute(mapper.aliasForSystemAttribute("class"), mapper.serializedClass(entry.getValue().getClass()));
                context.convertAnother(entry.getValue());
                writer.endNode();
                writer.endNode();
            }
        }
    }

    @Override
    protected void putCurrentEntryIntoMap(HierarchicalStreamReader reader, UnmarshallingContext context,Map map, Map target) {
        Object key;
        Object value;
        String nodeName = reader.getNodeName();
        String className = HierarchicalStreams.readClassAttribute(reader, mapper);
        if(entryName.equals(nodeName) && entryName.equals(className)){
            reader.moveDown();
            className = HierarchicalStreams.readClassAttribute(reader, mapper);
            Class itemType = mapper.realClass(className);
            key = context.convertAnother(target, itemType);
            reader.moveUp();
            reader.hasMoreChildren();
            reader.moveDown();
            className = HierarchicalStreams.readClassAttribute(reader, mapper);
            itemType = mapper.realClass(className);
            value = context.convertAnother(target, itemType);
            reader.moveUp();
        }else{  //如果Map的key是字符串类型，则xml的标签就是key
            key = nodeName;
            className = HierarchicalStreams.readClassAttribute(reader, mapper);
            Class itemType = mapper.realClass(className);
            value = context.convertAnother(target, itemType);
        }
        target.put(key, value);
    }

}
